import type { IGroup, IStroke, IStrokePaint, IUIInputData } from 'leafer-ui'
import { Ellipse, Group, Text } from 'leafer-ui'
import type { ICanvas, IGrid, IText } from 'src/interfaces/IBook'

import {
  create_boxtext,
  leafer_position,
  x_center_position,
} from './LeaferUtil'
import { BasePuzzleUtil } from './BasePuzzleUtil'
import { BoxText } from 'src/components/MyLeaferCutom'

import _ from 'lodash'
import type { ISolution } from 'src/interfaces/IAdvancedPuzzle'
import { Flow } from '@leafer-in/flow'
export class WordSearchPuzzleUtil extends BasePuzzleUtil {
  answers: Record<string, [number, number][]>
  letter_array: string[][]
  solution: ISolution
  words_legend: IText

  // 私有成员
  words_list_group: IGroup
  /**
   * @description: 创建单词搜索
   * @param {ICanvas} canvas: 信息字符串
   * @param {IText} title_model: 提示单词
   * @param {IText} instruction_model: 拼图单词的最长长度
   * @param {IGrid} words_grid_style: box框的样式
   * @param {*} answers: box框的样式
   * @param {*} letter_array: message的单词的提示下标的所处位置
   * @return {*}:
   */
  constructor(
    canvas: ICanvas,
    title_model: IText,
    instruction_model: IText,
    words_grid_style: IGrid,
    answers: Record<string, [number, number][]>,
    letter_array: string[][],
    solution: ISolution,
    words_legend: IText
  ) {
    super(canvas, title_model, instruction_model, [], words_grid_style)

    // 初始化 类成员变量
    this.answers = answers
    this.letter_array = letter_array
    this.solution = solution

    // 创建 words_list_groud
    this.words_list_group = new Group({
      x: 0,
      y: 0,
      editable: true,
      fill: '#FEB027',
      hitChildren: false,
    })
    this.words_legend = words_legend
  }
  generate_puzzle = (): void => {
    // 清除画布的元素
    this.answer_frame.clear()
    this.topic_frame.clear()

    // 生成 标题和副标题
    this.dram_title(this.title_model, this.instruction_model)
    // 生成 words 区域
    this.generate_words()
    // 生成答案样式
    this.generate_solution()
    // 生成 words list 区域
    this.generate_words_legend()

    // 将 title groud 添加进 frame
    this.title_group.x = x_center_position(
      this.title_group.boxBounds.width,
      this.topic_frame.width as number
    )
    this.title_group.y = this.canvas.height * 0.03
    this.answer_frame.add(this.title_group)
    this.topic_frame.add(this.title_group.clone())

    // 设置 word and  topic groud 的坐标位置
    const words_grid_ceterX = x_center_position(
      this.ans_words_group.boxBounds.width,
      this.answer_frame.width as number
    )
    this.ans_words_group.x = words_grid_ceterX
    this.topic_words_group.x = words_grid_ceterX

    this.ans_words_group.y =
      this.title_group.boxBounds.height +
      this.canvas.height * 0.06 +
      this.words_grid_style.offet_y
    this.topic_words_group.y =
      this.title_group.boxBounds.height +
      this.canvas.height * 0.06 +
      this.words_grid_style.offet_y
    // 将组添加进 fram
    this.answer_frame.add(this.ans_words_group)
    this.topic_frame.add(this.topic_words_group)

    // 将 words_list_group 添加进fram
    this.words_list_group.y =
      this.title_group.boxBounds.height +
      this.topic_words_group.boxBounds.height +
      this.canvas.height * 0.12 +
      this.words_grid_style.offet_y
    this.topic_frame.add(this.words_list_group)
    this.answer_frame.add(this.words_list_group.clone())
  }
  generate_words = () => {
    // 遍历 letter_array 将 字符数组渲染
    let row_num = 0
    for (const row of this.letter_array) {
      let col_num = 0
      for (const col of row) {
        // 获取实际渲染位置
        // 计算当前单词 的坐标
        const [rx, ry] = leafer_position({
          x: col_num,
          y: row_num,
          width: this.words_grid_style.width,
          height: this.words_grid_style.width,
          stroke: this.words_grid_style.stroke as IStrokePaint,
          white_border: this.white_border,
          x_offet: this.words_grid_style.offet_x,
          y_offet: this.words_grid_style.offet_y,
          x_interval: this.words_grid_style.x_interval,
          y_interval: this.words_grid_style.y_interval,
        })
        // 创建 答案box
        const text_box = create_boxtext({
          x: rx,
          y: ry,
          width: this.words_grid_style.width,
          height: this.words_grid_style.height,
          text: `${col.toUpperCase()}`,
          text_style: this.words_grid_style.text as IText,
          stroke: this.words_grid_style.stroke as IStroke,
        })
        this.topic_words_group.add(text_box)
        this.ans_words_group.add(text_box.clone())
        col_num++
      }
      row_num++
    }
  }
  generate_words_legend = () => {
    // 创建标题
    const title = new Text({
      x: 0,
      y: 0,
      height: this.words_legend.font.font_size,
      width: this.canvas.width,
      fontFamily: this.words_legend.font.font_name,
      fontSize: this.words_legend.font.font_size,
      textAlign: this.words_legend.text_align,
      verticalAlign: this.words_legend.vertical_align,
      fill: this.words_legend.font.font_color,
      text: `${this.words_legend.text}`,
    })
    // 通过for 循环创建文字
    const children: IUIInputData[] = []

    let word_max_len = 0
    let words: string[] = []
    for (const word in this.answers) {
      word_max_len = word.length > word_max_len ? word.length : word_max_len
      words.push(word)
    }
    words = words.map((word) => word.padEnd(word_max_len, ' '))
    for (const word of words) {
      const word_ui = new Text({
        width: this.canvas.width / 6,
        fontFamily: this.words_legend.font.font_name,
        fontSize: this.words_legend.font.font_size,
        textAlign: this.words_legend.text_align,
        verticalAlign: this.words_legend.vertical_align,
        fill: this.words_legend.font.font_color,
        text: `${word}`,
      })
      children.push(word_ui)
    }

    const flow = new Flow({
      x: x_center_position(
        this.canvas.width * 0.8,
        this.topic_frame.width as number
      ),
      y: Number(this.words_legend.font.font_size) * 4,
      flowWrap: true, // 沿 X 轴自动换行 //
      flowAlign: 'center', // 居中对齐 //
      fill: '#ffffff',
      gap: { x: 100, y: 100 },
      width: this.canvas.width * 0.8,
      height: 100,
      children: children,
    })
    this.words_list_group.add(flow)
    this.words_list_group.add(title)
  }
  /**
   * 渲染答案的样式
   */
  generate_solution = () => {
    for (const key in this.answers) {
      const letter_indexs = this.answers[key] as [number, number][]
      // 将数组坐标转换为 数学坐标
      const math_coordinate = this.array_2_math_coordinate(letter_indexs) as [
        number,
        number
      ][]
      // TOOD 需要将 switch 进行拆封，对于 高亮的选项 需要将生成word时就执行
      switch (this.solution.category) {
        case 'Border':
          this.ans_words_group.add(this.draw_solution_ellipse(math_coordinate))

          break
        case 'Highlight': {
          this.ans_words_group.add(
            this.draw_solution_highlight_color(key, math_coordinate)
          )
          break
        }
        default:
          break
      }
    }
  }

  draw_solution_ellipse = (coordinate: [number, number][]) => {
    // 数组长度
    const point_len = coordinate.length
    // 设置中心点坐标
    let center_point = [0, 0] as [number, number]
    // 判断是奇数还是偶数
    if (point_len % 2 == 1) {
      // 如果是奇数
      center_point = _.cloneDeep(coordinate[Math.ceil(point_len / 2) - 1]) as [
        number,
        number
      ]
    } else {
      const f_index = coordinate[point_len / 2 - 1] as [number, number]
      const l_index = coordinate[point_len / 2] as [number, number]
      center_point = [
        (f_index[0] + l_index[0]) / 2,
        (f_index[1] + l_index[1]) / 2,
      ]
    }
    center_point[0] += 0.5

    // 计算角度
    let theta: number = 0
    let hypotenuse = this.words_grid_style.width // 默认斜边长度为 边框宽度
    if (point_len >= 2) {
      const p1 = coordinate[0] as [number, number]
      const p2 = coordinate[1] as [number, number]
      const angle: number = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]) //弧度
      theta = angle * (180 / Math.PI) //角度

      if (Math.abs(theta) != 90) {
        const cos_num = Math.cos(angle)
        hypotenuse = Math.abs(hypotenuse / cos_num)
      }
    }

    // 计算直径
    const calibre = point_len * hypotenuse + point_len * 1

    // 计算真实坐标
    const [rx, ry] = leafer_position({
      x: center_point[0],
      y: center_point[1],
      width: this.words_grid_style.width,
      height: this.words_grid_style.height,
      stroke: this.words_grid_style.stroke as IStrokePaint,
      white_border: this.white_border,
      x_offet: this.words_grid_style.offet_x - calibre / 2,
      y_offet: this.words_grid_style.offet_y,
      x_interval: this.words_grid_style.x_interval,
      y_interval: this.words_grid_style.y_interval,
    })

    const ellipse = new Ellipse({
      width: calibre,
      height: this.words_grid_style.width,
      x: rx,
      y: ry,
      stroke: this.solution.stroke,
    })
    ellipse.rotateOf('center', theta)
    return ellipse
  }

  draw_solution_highlight_color = (
    word: string,
    coordinate: [number, number][]
  ): BoxText[] => {
    const lst: BoxText[] = []
    for (let i = 0; i < coordinate.length, i < word.length; i++) {
      const point = coordinate[i] as [number, number]
      const [rx, ry] = leafer_position({
        x: point[0],
        y: point[1],
        width: this.words_grid_style.width,
        height: this.words_grid_style.width,
        stroke: this.words_grid_style.stroke as IStrokePaint,
        white_border: this.white_border,
        x_offet: this.words_grid_style.offet_x,
        y_offet: this.words_grid_style.offet_y,
        x_interval: this.words_grid_style.x_interval,
        y_interval: this.words_grid_style.y_interval,
      })

      const text_box = new BoxText({
        text: word[i] as string,
        text_color: '#f14141',
        text_align: 'center',
        vertical_align: 'middle',
        font_size: this.words_grid_style.text?.font.font_size as number,
        width: this.words_grid_style.width,
        height: this.words_grid_style.height,
        x: rx,
        y: ry,
        editable: true,
        stroke: this.words_grid_style.stroke as IStroke,
        hitChildren: false, // 阻止直接选择子元素（防止父子选择冲突，可双击进入组内选择子元素）
      })

      lst.push(text_box)
    }
    return lst
  }

  /**
   * 将数组坐标转换为数学坐标
   * 在数组中（1，0）表示第二行第一个元素，在数学则表示它的位置x=1,y=0，实际应该为x=0,y=1
   * @param coordinate 二维数组的下标
   */
  array_2_math_coordinate(coordinate: [number, number][] | [number, number]) {
    if (Array.isArray(coordinate)) {
      const new_list = []
      for (const point of coordinate as [number, number][]) {
        new_list.push([point[1], point[0]])
      }
      return new_list
    } else {
      return [coordinate[1], coordinate[0]]
    }
  }
}
